/**
 *******************************************************************************
 * @FileName  : pan10x_gpio.h
 * @Author    : GaoQiu
 * @CreateDate: 2023-08-01
 * @Copyright : Copyright(C) Panchip
 *              All Rights Reserved.
 *******************************************************************************
 *
 * The information contained herein is confidential and proprietary property of
 * Panchip and is available under the terms of Commercial License Agreement
 * between Panchip and the licensee in separate contract or the terms described
 * here-in.
 *
 * This heading MUST NOT be removed from this file.
 *
 * Licensees are granted free, non-transferable use of the information in this
 * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
 *
 *******************************************************************************
 */

#ifndef PAN10X_GPIO_H_
#define PAN10X_GPIO_H_

#include "utils/track.h"
#include "platform/platform.h"
#include "pan10x_rcc.h"

#if 1//defined(IP_108)

#define GPIO_BASE_ADDR             (AHB1_PERIPH_BASE + 0x00020000UL)
#define GPIO_P0_ADDR               (GPIO_BASE_ADDR + 0x00)
#define GPIO_P1_ADDR               (GPIO_BASE_ADDR + 0x40)
#define GPIO_P2_ADDR               (GPIO_BASE_ADDR + 0x80)
#define GPIO_P3_ADDR               (GPIO_BASE_ADDR + 0xC0)
#define GPIO_P4_ADDR               (GPIO_BASE_ADDR + 0x100) // pan108
#define GPIO_P5_ADDR               (GPIO_BASE_ADDR + 0x140) // pan108


#define GPIO_AF_BASE_ADDR          (AHB1_PERIPH_BASE + 0x00030000UL)

/************************* GPIO Pin *******************************************/
#define GPIO_GRP_MASK             ((uint16_t)(0x0300))

#define GPIO0_GRP                 ((uint16_t)(0x0000))
#define GPIO1_GRP                 ((uint16_t)(0x0100))
#define GPIO2_GRP                 ((uint16_t)(0x0200))
#define GPIO3_GRP                 ((uint16_t)(0x0300))
#define GPIO4_GRP                 ((uint16_t)(0x0400))
#define GPIO5_GRP                 ((uint16_t)(0x0500))

/******* GPIO_Pin_x define *****/

#define GPIO_Pin_0                 ((uint16_t)(0x0001))
#define GPIO_Pin_1                 ((uint16_t)(0x0002))
#define GPIO_Pin_2                 ((uint16_t)(0x0004))
#define GPIO_Pin_3                 ((uint16_t)(0x0008))
#define GPIO_Pin_4                 ((uint16_t)(0x0010))
#define GPIO_Pin_5                 ((uint16_t)(0x0020))
#define GPIO_Pin_6                 ((uint16_t)(0x0040))
#define GPIO_Pin_7                 ((uint16_t)(0x0080))
#define GPIO_Pin_All               ((uint16_t)(0x00FF))
#define GPIO_Pin_None              ((uint16_t)(0x0000))

/******* GPIO_Pn define ********/
//P0
#define GPIO_P00                  (GPIO0_GRP + GPIO_Pin_0)
#define GPIO_P01                  (GPIO0_GRP + GPIO_Pin_1)
#define GPIO_P02                  (GPIO0_GRP + GPIO_Pin_2)
#define GPIO_P03                  (GPIO0_GRP + GPIO_Pin_3)
#define GPIO_P04                  (GPIO0_GRP + GPIO_Pin_4)
#define GPIO_P05                  (GPIO0_GRP + GPIO_Pin_5)
#define GPIO_P06                  (GPIO0_GRP + GPIO_Pin_6)
#define GPIO_P07                  (GPIO0_GRP + GPIO_Pin_7)

//P1
#define GPIO_P10                  (GPIO1_GRP + GPIO_Pin_0)
#define GPIO_P11                  (GPIO1_GRP + GPIO_Pin_1)
#define GPIO_P12                  (GPIO1_GRP + GPIO_Pin_2)
#define GPIO_P13                  (GPIO1_GRP + GPIO_Pin_3)
#define GPIO_P14                  (GPIO1_GRP + GPIO_Pin_4)
#define GPIO_P15                  (GPIO1_GRP + GPIO_Pin_5)
#define GPIO_P16                  (GPIO1_GRP + GPIO_Pin_6)
#define GPIO_P17                  (GPIO1_GRP + GPIO_Pin_7)

//P2
#define GPIO_P20                  (GPIO2_GRP + GPIO_Pin_0)
#define GPIO_P21                  (GPIO2_GRP + GPIO_Pin_1)
#define GPIO_P22                  (GPIO2_GRP + GPIO_Pin_2)
#define GPIO_P23                  (GPIO2_GRP + GPIO_Pin_3)
#define GPIO_P24                  (GPIO2_GRP + GPIO_Pin_4)
#define GPIO_P25                  (GPIO2_GRP + GPIO_Pin_5)
#define GPIO_P26                  (GPIO2_GRP + GPIO_Pin_6)
#define GPIO_P27                  (GPIO2_GRP + GPIO_Pin_7)

//P3
#define GPIO_P30                  (GPIO3_GRP + GPIO_Pin_0)
#define GPIO_P31                  (GPIO3_GRP + GPIO_Pin_1)
#define GPIO_P32                  (GPIO3_GRP + GPIO_Pin_2)
#define GPIO_P33                  (GPIO3_GRP + GPIO_Pin_3)
#define GPIO_P34                  (GPIO3_GRP + GPIO_Pin_4)
#define GPIO_P35                  (GPIO3_GRP + GPIO_Pin_5)
#define GPIO_P36                  (GPIO3_GRP + GPIO_Pin_6)
#define GPIO_P37                  (GPIO3_GRP + GPIO_Pin_7)

//P4
#define GPIO_P40                  (GPIO4_GRP + GPIO_Pin_0)
#define GPIO_P41                  (GPIO4_GRP + GPIO_Pin_1)
#define GPIO_P42                  (GPIO4_GRP + GPIO_Pin_2)
#define GPIO_P43                  (GPIO4_GRP + GPIO_Pin_3)
#define GPIO_P44                  (GPIO4_GRP + GPIO_Pin_4)
#define GPIO_P45                  (GPIO4_GRP + GPIO_Pin_5)
#define GPIO_P46                  (GPIO4_GRP + GPIO_Pin_6)
#define GPIO_P47                  (GPIO4_GRP + GPIO_Pin_7)

//P5
#define GPIO_P50                  (GPIO5_GRP + GPIO_Pin_0)
#define GPIO_P51                  (GPIO5_GRP + GPIO_Pin_1)
#define GPIO_P52                  (GPIO5_GRP + GPIO_Pin_2)
#define GPIO_P53                  (GPIO5_GRP + GPIO_Pin_3)
#define GPIO_P54                  (GPIO5_GRP + GPIO_Pin_4)
#define GPIO_P55                  (GPIO5_GRP + GPIO_Pin_5)
#define GPIO_P56                  (GPIO5_GRP + GPIO_Pin_6)
#define GPIO_P57                  (GPIO5_GRP + GPIO_Pin_7)


/*! GPIO Mode define */
#define GPIO_Mode_In              0x0
#define GPIO_Mode_PP_Out          0x1 /*!< Push-pull output */
#define GPIO_Mode_OD_Out          0x2 /*!< Open-drain output */
#define GPIO_Mode_Quasi           0x3 /*!< Quasi-bidirectional */

/*!< GPIO_Pull mode */


/*!< GPIO Interrupt Type */
#define GPIO_INT_Type_Edge         0
#define GPIO_INT_Type_Level        1

#define GPIO_IT_Mode_Falling   0x00000001ul
#define GPIO_IT_Mode_Rising    0x00010000ul
#define GPIO_IT_Mode_High      0x01010000ul
#define GPIO_IT_Mode_Low       0x01000001ul

/************************* GPIO AF *******************************************/
#define GPIO_AF_GPIO       0x00000000
#define GPIO_AF_1          0x00000001
#define GPIO_AF_2          0x00000100
#define GPIO_AF_3          0x00000101
#define GPIO_AF_4          0x00010000
#define GPIO_AF_5          0x00010001
#define GPIO_AF_6          0x00010100
#define GPIO_AF_7          0x00010101

typedef struct{
	__IO uint32_t Mode;
	__IO uint32_t IN_OFF;
	__IO uint32_t DO;
	__IO uint32_t DO_Msk;
	__IO uint32_t DI;
	__IO uint32_t DB_EN; /*!< de-bounce enable */
	__IO uint32_t INT_TYPE;
	__IO uint32_t INT_EN;
	__IO uint32_t INT_SRC;
}GPIO_Type_t;


void GPIO_DefInit(void);

static _inline_ void GPIO_Init(uint16_t GPIO_Pxx, uint8_t GPIO_Mode)
{
	if(GPIO_Pxx == GPIO_Pin_None)
		return;

	uint8_t grpId = (GPIO_Pxx >> 8) & 0x0f;
	uint8_t bit = GPIO_Pxx & 0xff;
	GPIO_Type_t *pGPIOx = (GPIO_Type_t *)(GPIO_BASE_ADDR + (grpId << 6));
	uint8_t pos = 0;

#if 0
	for(int i=0; i<8; i++){
		if(bit & (1<<i)){
			pos = i;
			break;
		}
	}
	pos <<= 1;
#else
	pos = (31 - __CLZ(bit)) << 1;
#endif
	uint32_t mode = pGPIOx->Mode;
	mode &= ~(0x3ul << pos);
	mode |= (GPIO_Mode << pos);
	pGPIOx->Mode = mode;

	if(GPIO_Mode == GPIO_Mode_In || GPIO_Mode == GPIO_Mode_Quasi){
		pGPIOx->IN_OFF &= ~(bit << 16);
		if(GPIO_Pxx == GPIO_P56){
			RCC_Wait3VSync();
		}
	}
}

static _inline_ void GPIO_SetPullUp(uint16_t GPIO_Pxx, uint8_t en)
{
	if(GPIO_Pxx == GPIO_Pin_None)
		return;

	uint8_t grpId = (GPIO_Pxx >> 8) & 0x0f;
	uint8_t bit = GPIO_Pxx & 0xff;
	GPIO_Type_t *pGPIOx = (GPIO_Type_t *)(GPIO_BASE_ADDR + (grpId << 6));

	uint32_t v = pGPIOx->IN_OFF;
	if(en){
		v |= (bit);
	}
	else{
		v &= ~(bit);
	}
	pGPIOx->IN_OFF = v;

#ifdef IP_108
	if(GPIO_Pxx == GPIO_P56){
		RCC_Wait3VSync();
	}
#endif
}

/* Only pan107 */
static _inline_ void GPIO_SetPullDown(uint16_t GPIO_Pxx, uint8_t en)
{
	if(GPIO_Pxx == GPIO_Pin_None)
		return;

	uint8_t grpId = (GPIO_Pxx >> 8) & 0x0f;
	uint8_t bit = GPIO_Pxx & 0xff;
	GPIO_Type_t *pGPIOx = (GPIO_Type_t *)(GPIO_BASE_ADDR + (grpId << 6));

	uint32_t v = pGPIOx->IN_OFF;
	if(en){
		v |= (bit<<8);
	}
	else{
		v &= ~(bit<<8);
	}
	pGPIOx->IN_OFF = v;
}

static _inline_ uint8_t GPIO_ReadInputBit(uint16_t GPIO_Pxx)
{
	uint8_t grpId = (GPIO_Pxx >> 8) & 0x0f;
	uint8_t bit = GPIO_Pxx & 0xff;
	GPIO_Type_t *pGPIOx = (GPIO_Type_t *)(GPIO_BASE_ADDR + (grpId << 6));

	return (pGPIOx->DI & bit) ? 1:0;
}

static _inline_ void GPIO_SetBit(uint16_t GPIO_Pxx)
{
	if(GPIO_Pxx == GPIO_Pin_None)
		return;

	uint8_t grpId = (GPIO_Pxx >> 8) & 0x0f;
	uint8_t bit = GPIO_Pxx & 0xff;
	GPIO_Type_t *pGPIOx = (GPIO_Type_t *)(GPIO_BASE_ADDR + (grpId << 6));

	pGPIOx->DO |= bit;
}

static _inline_ void GPIO_ResetBit(uint16_t GPIO_Pxx)
{
	if(GPIO_Pxx == GPIO_Pin_None)
		return;

	uint8_t grpId = (GPIO_Pxx >> 8) & 0x0f;
	uint8_t bit = GPIO_Pxx & 0xff;
	GPIO_Type_t *pGPIOx = (GPIO_Type_t *)(GPIO_BASE_ADDR + (grpId << 6));

	pGPIOx->DO &= ~bit;
}

static _inline_ void GPIO_ToggleEx(uint16_t GPIO_Pxx)
{
	if(GPIO_Pxx == GPIO_Pin_None)
		return;

	uint8_t grpId = (GPIO_Pxx >> 8) & 0x0f;
	uint8_t bit = GPIO_Pxx & 0xff;
	GPIO_Type_t *pGPIOx = (GPIO_Type_t *)(GPIO_BASE_ADDR + (grpId << 6));

    pGPIOx->DO ^= bit;
}

void GPIO_SetAFunc(uint16_t GPIO_Pxx, uint32_t GPIO_AF);

void GPIO_SetITEnable(uint16_t GPIO_Pxx, uint32_t GPIO_IT_Mode);
void GPIO_SetITDisable(uint16_t GPIO_Pxx);
uint8_t GPIO_GetITState(uint16_t GPIO_Pxx);
void GPIO_ClearITState(uint16_t GPIO_Pxx);

void GPIO_SetDebounceEnable(uint16_t GPIO_Pxx, uint8_t en);
void GPIO_SetWakeupLevel(uint8_t high);


#endif /* IP_108/IP_107 */

#endif /* PAN10X_GPIO_H_ */
